#!/usr/bin/env python
# -*- coding: utf-8 -*-
#

import os, os.path, time

from icewood import tinylog

from icewood.tca.tyrantindex import TyrantIndex

from hashlib import md5 as MD5


class   TestTyrantIndex(object) :
    
    def __init__(self, data_dir) :
        self.data_dir = os.sep.join((data_dir, 'tyrantindex'))

        self._logger = tinylog.getLogger(self.__class__.__name__)
        ## __init__()

    def setUp(self) :
        if os.path.exists( self.data_dir ) :
            self.removedirs( self.data_dir )
        os.makedirs( self.data_dir, 0777 )

        #index_filename = os.path.join(self.data_dir, 'index-test.tch')
        #config = { 'engine':'hdb', 'inum':2, 'bnum':1048576 * 8, 'apow':0, 'fpow':0, 'xmsiz':268435456 }
        index_filename = os.path.join(self.data_dir, 'index-test.tcb')
        config = { 'engine':'bdb', 'inum':32, 'lmemb':1024, 'nmemb':2048, 'bnum':1048576, 'apow':0, 'fpow':0, 'xmsiz':0 }
        self.index = TyrantIndex( index_filename,  config )
        ## setUp()

    def tearDown(self) :
        self.index.close()
        self.index = None
        ## tearDown()

    def removedirs(self, path) :
        items = os.listdir(path)
        for name in items :
            fullpath = os.sep.join((path, name))
            if os.path.isdir(fullpath) :
                self.removedirs(fullpath)
            else :
                os.remove(fullpath)

        os.rmdir(path)
        ## removedirs

    def __makeKeyValue(self, token) :
        k = MD5(token).digest()
        v = k
        
        return k[:12],v[:12]
        ## __makeKeyValue()


    def test_001(self) :
        '''test basic read and write
        '''
        self.index.vanish()

        for k,v in  (('KEY-HELLO','VALUE-HELLO'), ('KEY-WORLD','VALUE-WORLD')) :
            self.index.put(k, v)
            _v = self.index.get(k)
            assert v == _v

        for k,v in  (('KEY-HELLO','VALUE-HELLO'), ('KEY-WORLD','VALUE-WORLD')) :
            self.index.delete( k )

        for k,v in  (('KEY-HELLO','VALUE-HELLO'), ('KEY-WORLD','VALUE-WORLD')) :
            _v = self.index.get(k)
            assert _v is None
        ## test_001()

    def test_002(self, times) :
        '''test with md5
        '''
        self.index.vanish()

        TIMES = times

        self._logger.info('test-002 test PUT (%d records) ...', TIMES)
        time_start = time.time()
        t_start = time_start
        for i in xrange(TIMES) :
            k,v = self.__makeKeyValue( str(i) )
            self.index.put( k, v )

            if 0 == ((i+1) % 100000) :
                time_now = time.time()
                time_last = time_now - time_start
                tps = i / time_last

                t_last = time_now - t_start
                t_start = time_now
                t_tps = 100000 / t_last
                self._logger.info(' - PUT %.2E md5s last %.2f seconds, tps:%.2f (R-tps:%.2e)', i+1, time_last, tps, t_tps)
        time_last = time.time() - time_start
        tps = TIMES / time_last
        self._logger.info('  PUT %d md5s last %.2f seconds, tps:%.2f', TIMES, time_last, tps)

        self._logger.info('test-002 test GET (%d records) ...', TIMES)
        time_start = time.time()
        t_start = time_start
        for i in xrange(TIMES) :
            k,v_want = self.__makeKeyValue( str(i) )
            v = self.index.get( k )
            assert v == v_want

            if 0 == ((i+1) % 100000) :
                time_now = time.time()
                time_last = time_now - time_start
                tps = i / time_last

                t_last = time_now - t_start
                t_start = time_now
                t_tps = 100000 / t_last
                self._logger.info(' - GET %.2E md5s last %.2f seconds, tps:%.2f (R-tps:%.2e)', i+1, time_last, tps, t_tps)
        time_last = time.time() - time_start
        tps = TIMES / time_last
        self._logger.info('  GET %d md5s last %.2f seconds, tps:%.2f', TIMES, time_last, tps)

        self._logger.info('test-002 test done .')
        ## test_002()

    def test_003(self) :
        '''test switch function
        '''
        self.index.vanish()

        value_suffix = 'A' * 1024
        TIMES = 65536

        print 'Test002 : testing PUT ...'
        time_start = time.time()
        for i in xrange(TIMES) :
            key = 'HELLO-%09d' % i
            data = '-'.join((key, value_suffix))
            self.index.put( key, data )
        time_last = time.time() - time_start    
        tps = TIMES / time_last
        bw = tps * len(value_suffix) / 1048576.0
        print '        PUT %d times last %.2f seconds, tps:%.2f, bw:%.2f MB/s' % (TIMES, time_last, tps, bw)
        print 'Test002 : testing PUT done.'
        print self.index.stats()

        print 'Test002 : testing GET ...'
        time_start = time.time()
        for i in xrange(TIMES) :
            key = 'HELLO-%09d' % i
            data_want = '-'.join((key, value_suffix))
            data = self.index.get( key )
            if data != data_want :
                raise RuntimeError, 'DATA got %r, but want %r' % (data, data_want)
        time_last = time.time() - time_start    
        tps = TIMES / time_last
        bw = tps * len(value_suffix) / 1048576.0
        print '        GET %d times last %.2f seconds, tps:%.2f, bw:%.2f MB/s' % (TIMES, time_last, tps, bw)
        print 'Test002 : testing GET done.'

        print 'Test002 : testing DELETE ...'
        time_start = time.time()
        for i in xrange(TIMES) :
            key = 'HELLO-%09d' % i
            self.index.delete( key )
            data = self.index.get( key )
            if data :
                raise RuntimeError, 'DATA got %r, but want None' % data
        time_last = time.time() - time_start    
        tps = TIMES / time_last
        print '        DELETE %d times last %.2f seconds, tps:%.2f' % (TIMES, time_last, tps)
        print 'Test002 : testing DELETE done.'
        ## test_003()

    def run(self) :
        #print 'run test_001 ...'
        #self.setUp()
        #self.test_001()
        #self.tearDown()

        print 'run test_002 ...'
        for times in (1048576 * 5, 1048576 * 10) :
            self.setUp()
            self.test_002( times )
            self.tearDown()

        #print 'run test_003 ...'
        #self.setUp()
        #self.test_003()
        #self.tearDown()

        ## run()

    ## class TestTyrantIndex

if __name__ == '__main__' :

    from optparse import OptionParser
    parser = OptionParser()
    parser.add_option("", "--data-dir", dest="data_dir", type="string", 
                        help='path to data directory')

    parser.add_option("-l", "--logconf", dest="logconfig", type="string",
                        help='path to logging configure file')

    parser.add_option("-d", "--debug", dest="debug", action="store_true", default=False,
                        help='show debug information')

    (options, args) = parser.parse_args()
    if not options.data_dir :
        parser.print_help( sys.stdout )
        sys.exit(0)

    if options.logconfig :
        tinylog.loadConfigure( options.logconfig )

    if options.debug :
        logger = tinylog.getLogger()
        logger.setLevel(logging.LEVEL_DEBUG)

    t = TestTyrantIndex( options.data_dir )
    t.run()


